/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// TGUI - Texus' Graphical User Interface
// Copyright (C) 2012-2025 Bruno Van de Velde (vdv_b@tgui.eu)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
//    you must not claim that you wrote the original software.
//    If you use this software in a product, an acknowledgment
//    in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
//    and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef TGUI_FONT_HPP
#define TGUI_FONT_HPP

#include <TGUI/String.hpp>
#include <TGUI/Rect.hpp>

#include <cstdint>
#include <string>
#include <cstddef>
#include <memory>

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace tgui
{
    class BackendFont;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Information about a glyph in the font
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    struct TGUI_API FontGlyph
    {
        float     advance = 0;  //!< Offset to move horizontally to the next character
        FloatRect bounds;       //!< Bounding rectangle of the glyph, in coordinates relative to the baseline
        UIntRect  textureRect;  //!< Texture coordinates of the glyph inside the font's texture
    };

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// @brief Wrapper around the backend-specific font. All copies of the font will share the same internal font resource.
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    class TGUI_API Font
    {
    public:

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Changes the global font that is used for all new widgets
        /// @param font  New global font
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        static void setGlobalFont(const Font& font);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the global font that is used for all new widgets
        /// @return Global font
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD static Font getGlobalFont();

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Default constructor which will set the font to nullptr
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Font(std::nullptr_t = nullptr) noexcept;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Constructor to create the font from a string (filename by default)
        ///
        /// @param id  String to pass to the Deserializer class to load the font
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Font(const String& id);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Constructor to create the font from a string (filename by default)
        ///
        /// @param id  String to pass to the Deserializer class to load the font
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Font(const char* id);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Constructor to create the font from a byte array
        /// @param data         Pointer to the file data in memory
        /// @param sizeInBytes  Size of the data to load, in bytes
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Font(const void* data, std::size_t sizeInBytes);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Constructor to create the font from an internal backend font
        ///
        /// @param backendFont  Internal font to use
        /// @param id           Id of the font (usually filename)
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        Font(std::shared_ptr<BackendFont> backendFont, String id);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the id that was used to load the font
        ///
        /// @return Id of the font or an empty string when no id was passed when this object was created
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD const String& getId() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Converts the font to a boolean to check if it is a nullptr of not
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        operator bool() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Compares the font with a nullptr
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool operator==(std::nullptr_t) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Compares the font with a nullptr
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool operator!=(std::nullptr_t) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Compares the font with another one
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool operator==(const Font& right) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Compares the font with another one
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool operator!=(const Font& right) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Retrieve a glyph of the font
        ///
        /// If the font is a bitmap font, not all character sizes might be available. If the glyph is not available at the
        /// requested size, an empty glyph is returned.
        ///
        /// @param codePoint        Unicode code point of the character to get
        /// @param characterSize    Reference character size
        /// @param bold             Retrieve the bold version or the regular one?
        /// @param outlineThickness Thickness of outline (when != 0 the glyph will not be filled)
        ///
        /// @return The glyph corresponding to codePoint and characterSize
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD FontGlyph getGlyph(char32_t codePoint, unsigned int characterSize, bool bold, float outlineThickness = 0) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the kerning offset of two glyphs
        ///
        /// The kerning is an extra offset (negative) to apply between two glyphs when rendering them, to make the pair look
        /// more "natural". For example, the pair "AV" have a special kerning to make them closer than other characters.
        /// Most of the glyphs pairs have a kerning offset of zero, though.
        ///
        /// @param first         Unicode code point of the first character
        /// @param second        Unicode code point of the second character
        /// @param characterSize Size of the characters
        /// @param bold          Are the glyphs bold or regular?
        ///
        /// @return Kerning value for first and second, in pixels
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD float getKerning(char32_t first, char32_t second, unsigned int characterSize, bool bold = false) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the line spacing
        ///
        /// Line spacing is the vertical offset to apply between two consecutive lines of text.
        ///
        /// @param characterSize Size of the characters
        ///
        /// @return Line spacing, in pixels
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD float getLineSpacing(unsigned int characterSize) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the height required to render a line of text
        ///
        /// @param characterSize Size of the characters
        ///
        /// @return Sum of font ascent and descent
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD float getFontHeight(unsigned int characterSize) const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Enable or disable the smooth filter
        ///
        /// When the filter is activated, the font appears smoother so that pixels are less noticeable. However if you want
        /// the font to look exactly the same as its source file then you should disable it.
        /// The smooth filter is enabled by default.
        ///
        /// @param smooth  True to enable smoothing, false to disable it
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        void setSmooth(bool smooth);

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Tell whether the smooth filter is enabled or not
        ///
        /// @return True if smoothing is enabled, false if it is disabled
        ///
        /// @see setSmooth
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD bool isSmooth() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// @brief Returns the internal font
        /// @return Backend font that is used internally
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        TGUI_NODISCARD std::shared_ptr<BackendFont> getBackendFont() const;

        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    private:

        std::shared_ptr<BackendFont> m_backendFont;
        String m_id;
    };

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // TGUI_FONT_HPP
